package com.njuse.seecjvm.instructions.invoke;

import com.njuse.seecjvm.instructions.base.Index16Instruction;
import com.njuse.seecjvm.memory.jclass.InitState;
import com.njuse.seecjvm.memory.jclass.JClass;
import com.njuse.seecjvm.memory.jclass.Method;
import com.njuse.seecjvm.memory.jclass.runtimeConstantPool.constant.Constant;
import com.njuse.seecjvm.memory.jclass.runtimeConstantPool.constant.ref.MethodRef;
import com.njuse.seecjvm.runtime.StackFrame;
import com.njuse.seecjvm.runtime.Vars;
import com.njuse.seecjvm.runtime.struct.Slot;

public class INVOKE_STATIC extends Index16Instruction {

    /**
     * TODO 实现这条指令，注意其中的非标准部分：
     * 1. TestUtil.equalInt(int a, int b): 如果a和b相等，则跳过这个方法，
     * 否则抛出`RuntimeException`, 其中，这个异常的message为
     * ：${第一个参数的值}!=${第二个参数的值}
     * 例如，TestUtil.equalInt(1, 2)应该抛出
     * RuntimeException("1!=2")
     *
     * 2. TestUtil.fail(): 抛出`RuntimeException`
     *
     * 3. TestUtil.equalFloat(float a, float b): 如果a和b相等，则跳过这个方法，
     * 否则抛出`RuntimeException`. 对于异常的message不作要求
     *
     */
    @Override
    public void execute(StackFrame frame) {
   	
        JClass currentClz = frame.getMethod().getClazz();
        Constant methodRef = currentClz.getRuntimeConstantPool().getConstant(super.index);
        Method method = ((MethodRef) methodRef).resolveMethodRef();
        

    	
    	
        if (method.isNative()) return;
        
        //记得判断这个类有没有被init过
        JClass clazz=method.getClazz();
    	if (clazz.getInitState()==InitState.PREPARED) {
    		frame.setNextPC(frame.getNextPC()-3);//倒退回去，如果没有初始化完成，那就倒退回去再做一遍
    		clazz.initClass(frame.getThread(), clazz);
    		return;
    	}
    	
    	
        StackFrame methodFrame = new StackFrame(frame.getThread(), method, method.getMaxStack(), method.getMaxLocal());
        int argc = method.getArgc(); 
        Slot[] argv = new Slot[argc];
        for (int i = 0; i < argc; i++) {
            argv[i] = frame.getOperandStack().popSlot();
        }     
        

        
        Vars localVars = methodFrame.getLocalVars();
        for (int i = 0; i < argv.length; i++) {
            localVars.setSlot(i, argv[argc - i-1]);
        }
        
 
        
        if (method.getName().equals("equalInt")) {
        	int a=localVars.getInt(0);
        	int b=localVars.getInt(1);
        	if (a!=b) throw new RuntimeException(a+"!="+b);

        }
        if (method.getName().equals("equalFloat")) {
        	float a=localVars.getFloat(0);
        	float b=localVars.getFloat(1);
        	if (a!=b) throw new RuntimeException();

        }
        
        
        if (method.getName().equals("fail")) {
        throw new RuntimeException( );
        }
      
    	
        
        frame.getThread().pushFrame(methodFrame);    


}
}
